package org.example.security.config;

import org.example.security.autoconfiguration.SecurityProperties;
import org.example.security.filter.JwtAuthenticationTokenFilter;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * security配置
 */
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private SecurityProperties securityProperties;
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    private AuthenticationEntryPoint authenticationEntryPoint;
    private AccessDeniedHandler accessDeniedHandler;


    /**
     * 构造器注入私有属性
     * @param securityProperties 属性
     * @param jwtAuthenticationTokenFilter jwt token认证过滤器
     * @param authenticationEntryPoint 认证失败处理器
     * @param accessDeniedHandler  授权失败处理器
     */
    public  SecurityConfiguration(SecurityProperties securityProperties, JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter,
                                  AuthenticationEntryPoint authenticationEntryPoint, AccessDeniedHandler accessDeniedHandler) {
        this.securityProperties = securityProperties;
        this.jwtAuthenticationTokenFilter = jwtAuthenticationTokenFilter;
        this.authenticationEntryPoint = authenticationEntryPoint;
        this.accessDeniedHandler = accessDeniedHandler;
    }


    /**
     * 放行白名单
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        if (securityProperties.getIgnoreUrls() != null && securityProperties.getIgnoreUrls().size() > 0) {
            for (String ignoreUrl : securityProperties.getIgnoreUrls()) {
                web.ignoring().antMatchers(ignoreUrl);
            }
        }
        // 注意点： 预检请求要直接放行，否则预检请求没有携带token会导致401，从而误认为是跨域配置错误
        web.ignoring().antMatchers(HttpMethod.OPTIONS,"/**");
    }

    /**
     * security安全配置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //使用JWT，不需要csrf
        http.csrf()
                .disable()
                //基于token，不需要session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                //所有请求都要求认证
                .anyRequest()
                .authenticated()
                .and()
                //禁用缓存
                .headers()
                .cacheControl();
        //添加jwt 登录授权过滤器
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        http.exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)
                .authenticationEntryPoint(authenticationEntryPoint);
    }
}
